#include<mempool.h>

static slabclass* slab_size2class[SLAB_SIZE_MAX+1];

/**
 * mempool_init()
 * 初始化内存池，生成对应的size->slabclass映射
 * 对于每个slabclass进行第一次的内存分配
 * 
*/
void mempool_init(){
    //slabclass 策略：最小为a 公比为p 最大为SLAB_SIZE_MAX
    double tmp = 10, p = 1.2;
    while(1){
        int tmpsize = min(SLAB_SIZE_MAX,(int)tmp);
        //slab_size2class[tmpsize]
        slab_size2class[tmpsize] =(slabclass*)slab_size2class;
        if (tmpsize == SLAB_SIZE_MAX)
            break;
        tmp *= p;
    }
    //前面可以更换策略，这里进行具体的内存分配和映射表建立
    slabclass *pre;
    for (int i = SLAB_SIZE_MAX; i >= 0; i--)
    {
        if(slab_size2class[i]==0){
            slab_size2class[i] = pre;
            continue;
        }
        int slabsize = sizeof(slab) + i;
        int slabcnt = (SLABCLASS_MALLOC_SIZE - sizeof(slabclass)) / slabsize;
        auto ptr = (uint8_t *)malloc(slabsize * slabcnt + sizeof(slabclass));
        slab_size2class[i] = (slabclass *)ptr;
        ((slabclass *)ptr)->size = i;
        ((slabclass *)ptr)->flg = 0;
        ptr += sizeof(slabclass);

        //新建链表
        slab *preslab = nullptr;
        slab_size2class[i]->tail = (slab*)ptr;
        for (int j = 0; j < slabcnt;j++){
            auto tmpslab = (slab *)ptr;
            tmpslab->nxt = preslab;
            tmpslab->scls = slab_size2class[i];
            tmpslab->ismalloc = false;
            preslab = tmpslab;
            ptr += slabsize;
        }
        slab_size2class[i]->tail = (slab *)(ptr - slabsize);

        //完善映射表
        pre = slab_size2class[i];
    }
    LOG_MSG("MEMPOOL INIT");
}

/*
* mempool_free(void*p)
* 回收一块内存
*
*/
void mempool_free(void*p){
    auto ptr =(slab *)p;
    ptr--;
    if(ptr->ismalloc){
        free(ptr);
        return;
    }
    ptr->nxt = nullptr;
    while (_CAS(&ptr->scls->tail->nxt, nullptr, ptr));
    ptr->scls->tail = ptr;
}


/*
* mempool_malloc(int size)
* 申请一块内存，如果没有多余的空间，自动扩容
* 如果申请的范围严格大于SLAB_SIZE_MAX 自动调用malloc
* 其实上申请的空间是size+sizeof(slab)
*
*/
void* mempool_malloc(int size){
    assert(size > 0);
    if(size>SLAB_SIZE_MAX){
        auto ret = (slab *)malloc(size + sizeof(slab));
        return ++ret;
    }
    auto scls = slab_size2class[size];
    while(1){
        auto head = scls->head;
        auto hnxt = head->nxt;
        if(hnxt==nullptr){
            //内存池为空：两种情况：申请中或已经申请失败
            if(scls->flg==1)
                return nullptr;
            if(_CAS(&scls->flg,0,2))
                assert(pthread_create(&scls->worktrd,NULL,slabclass_malloc,scls)==0);
            continue;
        }
        if(_CAS(&scls->head,head,hnxt)){
            return ++head;
        }
    }
    return nullptr;
}

/**
 * slabclass_malloc
 * 申请一大块内存，我想开个小线程慢慢这么干
 */
void* slabclass_malloc(void *p){
    //此函数调用时，CAS，不会出现并发调用
    //调用前已经置位scls->flg=2 结束后scls->flg=0;
    //只要内存池head->nxt!=nullptr 阻塞的线程就会开工
    auto scls = (slabclass *)p;
    int slabsize = sizeof(slab) + scls->size;
    int slabcnt = SLABCLASS_MALLOC_SIZE / slabsize;
    auto slabptr = (uint8_t*)malloc(slabsize * slabcnt);
    while(slabcnt){
        auto tmp = (slab *)slabptr;
        tmp->scls = scls;
        tmp->nxt = nullptr;
        while(_CAS(&scls->tail->nxt,nullptr,tmp));
        scls->tail = tmp;
        slabptr += slabsize;
        slabcnt--;
    }
    scls->flg = 0;
    return nullptr;
}